---
title: 使用环境变量
sidebar:
  label: 环境变量
description: 了解如何在 Astro 项目中使用环境变量。
i18nReady: true
---
import PackageManagerTabs from '~/components/tabs/PackageManagerTabs.astro'
import ReadMore from '~/components/ReadMore.astro';

Astro 使你可以使用 [Vite 内置的环境变量支持](#vite-内置支持)，并为你的项目包含了一些 [默认环境变量](#默认环境变量)，让你可以访问当前项目的配置值（例如 `site`、`base`），无论你的项目是在开发还是生产环境中运行。

Astro 也提供了一种 [使用和组织类型安全的环境变量](#类型安全的环境变量) 的方法。它可以在 Astro 上下文中使用（例如 Astro 组件、路由和端点、UI 框架组件、中间件），并通过 [Astro 配置中的 schema](/zh-cn/reference/configuration-reference/#env) 进行管理。

## Vite 内置支持

Astro 使用 Vite 的内置环境变量支持，这些变量在构建时静态替换，让你可以 [使用任何 Vite 的方法](https://cn.vite.dev/guide/env-and-mode.html)来处理它们。

注意，虽然 _所有_ 环境变量都可以在服务器端代码中使用，但出于安全考虑，只有以 `PUBLIC_` 为前缀的环境变量可以在客户端代码中使用。

```ini title=".env"
SECRET_PASSWORD=password123
PUBLIC_ANYBODY=there
```

在这个例子中，`PUBLIC_ANYBODY`（通过 `import.meta.env.PUBLIC_ANYBODY` 访问）将在服务器端或客户端代码中可用，而 `SECRET_PASSWORD`（通过 `import.meta.env.SECRET_PASSWORD` 访问）将仅在服务器端可用。

:::caution
`.env` 不会在 [配置文件](#在-astro-配置文件中) 中加载。
:::

### TypeScript 智能提示

默认情况，Astro 在 `astro/client.d.ts` 中为 `import.meta.env` 提供类型定义。

当在 `.env.[mode]` 文件中定义了更多的自定义环境变量，你可能想要得到以 `PUBLIC_` 前缀的自定义环境变量的 TypeScript 智能提示。

为了实现这一点，你可以在 `src/` 中创建一个 `env.d.ts`，以 [扩展全局类型](/zh-cn/guides/typescript/#扩展全局类型) 并配置 `ImportMetaEnv`：

```ts title="src/env.d.ts"
interface ImportMetaEnv {
  readonly DB_PASSWORD: string;
  readonly PUBLIC_POKEAPI: string;
  // 更多环境变量…
}

interface ImportMeta {
  readonly env: ImportMetaEnv;
}
```

## 默认环境变量

Astro 包括了几个开箱即用的环境变量：

- `import.meta.env.MODE`：站点的运行模式。在运行 `astro dev` 时为 `development`，在运行 `astro build` 时为 `production`。
- `import.meta.env.PROD`：当你的站点以`production`模式运行时为`true`；否则为`false`。
- `import.meta.env.DEV`：当你的站点以`development`模式运行时为`true`；否则为`false`。（总是和 `import.meta.env.PROD` 相反）。
- `import.meta.env.BASE_URL`：为站点提供服务的基础 url。它由 [`base` 配置项](/zh-cn/reference/configuration-reference/#base) 决定。
- `import.meta.env.SITE`：特指项目中 `astro.config` 中的 [`site` 项](/zh-cn/reference/configuration-reference/#site)。
- `import.meta.env.ASSETS_PREFIX`：如果设置了 [`build.assetsPrefix` 配置项](/zh-cn/reference/configuration-reference/#buildassetsprefix)，则指定 Astro 生成的资源链接的前缀。可以用于创建不由 Astro 处理的资源链接。

你可以将它们当作其他任意的环境变量来使用。

```ts utils.ts
const isProd = import.meta.env.PROD;
const isDev = import.meta.env.DEV;
```

## 设置环境变量

### `.env` 文件

环境变量会从项目目录中的 `.env` 文件中加载。

只需在项目目录下创建 `.env` 文件，并在其中添加一些变量。

```ini title=".env"
# 这只有在服务器上运行时才会有效！
DB_PASSWORD="foobar"

# 这在什么地方都有效！
PUBLIC_POKEAPI="https://pokeapi.co/api/v2"
```

你也可以添加 `.production`、`.development` 或自定义模式名称到文件名中（例如 `.env.testing`、`.env.staging`）。这样可以让你在不同的时间使用不同的环境变量集。

`astro dev` 和 `astro build` 命令默认分别使用 `"development"` 和 `"production"` 模式。你可以通过 [`--mode` 标志](/zh-cn/reference/cli-reference/#--mode-string) 运行这些命令，传递不同的 `mode` 值并加载匹配的 `.env` 文件。

这允许你运行开发服务器或构建你的站点时连接到不同的 API：

<PackageManagerTabs>
 <Fragment slot="npm">
    ```shell
    # 运行开发服务器连接到一个 “staging” API
    npm run astro dev -- --mode staging

    # 构建一个连接到 “production” API 的站点，并输出额外的调试信息
    npm run astro build -- --devOutput

    # 构建一个连接到 “testing” API 的站点
    npm run astro build -- --mode testing
    ```
 </Fragment>
 <Fragment slot="pnpm">
    ```shell
    # 运行开发服务器连接到一个 “staging” API
    pnpm astro dev --mode staging

    # 构建一个连接到 “production” API 的站点，并输出额外的调试信息
    pnpm astro build --devOutput

    # 构建一个连接到 “testing” API 的站点
    pnpm astro build --mode testing
    ```
 </Fragment>
  <Fragment slot="yarn">
    ```shell
    # 运行开发服务器连接到一个 “staging” API
    yarn astro dev --mode staging

    # 构建一个连接到 “production” API 的站点，并输出额外的调试信息
    yarn astro build --devOutput

    # 构建一个连接到 “testing” API 的站点
    yarn astro build --mode testing
    ```
 </Fragment>
</PackageManagerTabs>

对于更多关于 `.env` 文件的信息，[请查看 Vite 文档](https://cn.vite.dev/guide/env-and-mode.html#env-files)。

### 在 Astro 配置文件中

Astro 在加载其他文件之前会评估配置文件。这意味着你不能在 `astro.config.mjs` 中使用 `import.meta.env` 来访问 `.env` 文件中设置的环境变量。

你可以在配置文件中使用 `process.env` 来访问其他环境变量，例如 [由 CLI 设置的环境变量](#使用-cli)。

你也可以使用 [Vite 的 `loadEnv` 辅助函数](https://cn.vite.dev/config/#using-environment-variables-in-config) 手动加载 `.env` 文件。

```js title="astro.config.mjs"
import { loadEnv } from "vite";

const { SECRET_PASSWORD } = loadEnv(process.env.NODE_ENV, process.cwd(), "");
```

:::note
`pnpm` 不允许你导入未直接安装在项目中的模块。如果你使用 `pnpm`，你需要安装 `vite` 来使用 `loadEnv` 辅助函数。

```sh
pnpm add -D vite
```
:::

### 使用 CLI

你也还可以在运行项目时添加环境变量：

<PackageManagerTabs>
 <Fragment slot="yarn">
    ```shell
    PUBLIC_POKEAPI=https://pokeapi.co/api/v2 yarn run dev
    ```
 </Fragment>
 <Fragment slot="npm">
    ```shell
    PUBLIC_POKEAPI=https://pokeapi.co/api/v2 npm run dev
    ```
 </Fragment>
 <Fragment slot="pnpm">
    ```shell
    PUBLIC_POKEAPI=https://pokeapi.co/api/v2 pnpm run dev
    ```
 </Fragment>
</PackageManagerTabs>

## 获取环境变量

在 Astro 中，环境变量是通过 `import.meta.env` 访问的，使用的是 [在 ES2020 中添加的 `import.meta` 功能](https://tc39.es/ecma262/2020/#prod-ImportMeta)，而不是 `process.env`。

例如，使用 `import.meta.env.PUBLIC_POKEAPI` 来获取 `PUBLIC_POKEAPI` 环境变量。

```js /(?<!//.*)import.meta.env.[A-Z_]+/
// 当 import.meta.env.SSR === true
const data = await db(import.meta.env.DB_PASSWORD);

// 当 import.meta.env.SSR === false
const data = fetch(`${import.meta.env.PUBLIC_POKEAPI}/pokemon/squirtle`);
```

使用 SSR 时，可以根据所使用的 SSR 适配器，在运行时访问环境变量。对于大部分适配器，可以通过 `process.env` 访问环境变量，但有一些适配器在工作时有所不同。Deno 适配器则需要使用 `Deno.env.get()`。在使用 Cloudflare 适配器时，可以参阅如何 [访问 Cloudflare 运行时](/zh-cn/guides/integrations-guide/cloudflare/#cloudflare-运行时) 以处理环境变量。Astro 会检查服务器环境中的变量，如果这些变量不存在，则会在 `.env` 文件中查找它们。

## 类型安全的环境变量

`astro:env` 允许你为 [设置的环境变量](#设置环境变量) 配置一个类型安全的 schema。这允许你指定它们是否应该在服务器端或客户端上可用，并定义它们的数据类型和其他属性。

<ReadMore>在开发适配器？查看如何 [使适配器与 `astro:env` 兼容](/zh-cn/reference/adapter-reference/#envgetsecret)。</ReadMore>

### 基础使用

#### 定义你的 schema

要定义一个 schema，将 `env.schema` 选项添加到你的 Astro 配置中：

```js title="astro.config.mjs" ins={4-8}
import { defineConfig } from "astro/config";

export default defineConfig({
  env: {
    schema: {
      // ...
    }
  }
})
```

然后，你可以使用 `envField` 辅助函数 [将变量注册为字符串、数字、枚举或布尔值](#数据类型)。为每个变量提供 `context`（`"client"` 或 `"server"`）和 `access`（`"secret"` 或 `"public"`）来定义 [环境变量的类型](#变量类型)，并在对象中传递任何额外的属性，例如 `optional` 或 `default`：

```js title="astro.config.mjs" ins="envField"
import { defineConfig, envField } from "astro/config";

export default defineConfig({
  env: {
    schema: {
      API_URL: envField.string({ context: "client", access: "public", optional: true }),
      PORT: envField.number({ context: "server", access: "public", default: 4321 }),
      API_SECRET: envField.string({ context: "server", access: "secret" }),
    }
  }
})
```

类型将在运行 `astro dev` 或 `astro build` 时为你生成，但你也可以运行 `astro sync` 仅生成类型。

#### 使用你的 schema 中定义的变量

从对应的 `/client` 或 `/server` 模块导入并使用你定义的变量：

```astro
---
import { API_URL } from "astro:env/client";
import { API_SECRET_TOKEN } from "astro:env/server";

const data = await fetch(`${API_URL}/users`, {
	method: "GET",
	headers: {
		"Content-Type": "application/json",
		"Authorization": `Bearer ${API_SECRET_TOKEN}`
	},
})
---

<script>
  import { API_URL } from "astro:env/client";
  
  fetch(`${API_URL}/ping`)
</script>
```

### 变量类型

环境变量分为三种，由你在 schema 中定义的 `context`（`"client"` 或 `"server"`）和 `access`（`"secret"` 或 `"public"`）设置决定：

- **公共的客户端变量**：这些变量最终会出现在你的最终客户端和服务器包中，并且可以通过 `astro:env/client` 模块从客户端和服务器中访问：

   ```js
   import { API_URL } from "astro:env/client";
   ```

- **公共的服务器变量**：这些变量最终会出现在你的最终服务器包中，并且可以通过 `astro:env/server` 模块从服务器中访问：

   ```js
   import { PORT } from "astro:env/server";
   ```

- **私密的服务器变量**：这些变量不会出现在你的最终包中，只能通过 `astro:env/server` 模块从服务器中访问：

   ```js
   import { API_SECRET } from "astro:env/server";
   ```

   默认情况下，私密变量只在运行时验证。你可以通过 [配置 `validateSecrets: true`](/zh-cn/reference/configuration-reference/#envvalidatesecrets) 来在启动时验证私密变量。


:::note
不支持 **私密的客户端变量**，因为没有一种可以将这些数据安全发送到客户端的方式。所以，不能在你的 schema 中配置 `context: "client"` 和 `access: "secret"`。
:::

### 数据类型

目前支持四种数据类型：字符串、数字、枚举和布尔值：

```js
import { envField } from "astro/config";

envField.string({
   // context & access
   optional: true,
   default: "foo",
})

envField.number({
   // context & access
   optional: true,
   default: 15,
})

envField.boolean({
   // context & access
   optional: true,
   default: true,
})

envField.enum({
   // context & access
   values: ["foo", "bar", "baz"],
   optional: true,
   default: "baz",
})
```

<ReadMore>有关验证字段的完整列表，请参阅 [`envField` API 参考](/zh-cn/reference/configuration-reference/#envschema)。</ReadMore>

### 动态检索私密变量

尽管定义了你的 schema，你可能想要检索某一个私密变量的原始值，或者检索未在你的 schema 中定义的私密变量。在这种情况下，你可以使用 `astro:env/server` 导出的 `getSecret()`：

```js
import {
   FOO, // boolean
   getSecret
} from "astro:env/server";

getSecret("FOO"); // string | undefined
```

<ReadMore>在 [API 参考](/zh-cn/reference/modules/astro-env/#getsecret) 中了解更多。</ReadMore>

### 限制

`astro:env` 是一个虚拟模块，这意味着它只能在 Astro 上下文中使用。例如，你可以在以下情况下使用它：

- 中间件
- Astro 路由和端点
- Astro 组件
- 框架组件
- 模块

你不能在以下情况下使用它，必须使用 `process.env`：

- `astro.config.mjs`
- Script 脚本
